package controllers

import (
	"github.com/ahmetb/go-linq/v3"
	"goconfcenter/core/consts"
	"goconfcenter/core/enums"
	"goconfcenter/core/response"
	"goconfcenter/models"
	"goconfcenter/pkg/snowflake"
	"goconfcenter/service"
	"goconfcenter/service/dto/bus"
	"strconv"
	"strings"

	"go.uber.org/zap"

	"github.com/gin-gonic/gin"
)

type ResourceController struct {
}

func (c *ResourceController) TreeGrid(ctx *gin.Context) {
	list := service.ResourceServiceInstance().GetList()
	response.Success(ctx, consts.CurdStatusOkMsg, list)
	return
}

func (c *ResourceController) Get(ctx *gin.Context) {
	id, _ := strconv.ParseInt(ctx.DefaultQuery("id", "0"), 10, 64)
	result := service.ResourceServiceInstance().Get(id)
	response.Success(ctx, consts.CurdStatusOkMsg, result)
	return
}

func (c *ResourceController) Edit(ctx *gin.Context) {
	resource := new(models.Resource)
	if err := ctx.ShouldBindJSON(resource); err != nil {
		zap.L().Error("请求参数异常", zap.Error(err))
		response.ErrorParam(ctx, "")
		return
	}
	oldResource := service.ResourceServiceInstance().Get(resource.ID)
	oldResource.Name = resource.Name
	oldResource.Title = resource.Title
	oldResource.Status = resource.Status
	oldResource.AuthorCode = resource.AuthorCode
	result := service.ResourceServiceInstance().Update(oldResource)
	if result {
		response.Success(ctx, consts.CurdStatusOkMsg, oldResource.ID)
	} else {
		response.Fail(ctx, consts.BusinessFail, consts.BusinessFailMsg, "编辑失败")
	}
	return
}

func (c *ResourceController) UpdateResourceTree(ctx *gin.Context) {
	routerData := make([]bus.Router, 0)
	if err := ctx.ShouldBindJSON(&routerData); err != nil {
		zap.L().Error("请求参数异常", zap.Error(err))
		response.ErrorParam(ctx, "")
		return
	}
	if routerData == nil || len(routerData) == 0 {
		response.Fail(ctx, consts.BusinessFail, consts.BusinessFailMsg, "更新资源树失败")
		return
	}
	//获取所有已存在的项
	exists := service.ResourceServiceInstance().GetList()
	existsIds := make([]int64, 0)
	linq.From(exists).SelectT(func(a *models.ResourcePoJo) int64 {
		return a.ID
	}).ToSlice(&existsIds)
	forSaveIds := make([]int64, 0)
	dealRouters(routerData, 0, exists, &forSaveIds)
	deleteIds := make([]int64, 0)
	linq.From(existsIds).Except(linq.From(forSaveIds)).ToSlice(&deleteIds)
	if len(deleteIds) > 0 {
		service.ResourceServiceInstance().BathDelete(&deleteIds)
	}
}

func dealRouters(data []bus.Router, pid int64, exists []*models.ResourcePoJo, forSaveIds *[]int64) {
	for _, r := range data {
		curResource := new(models.Resource)
		one := linq.From(exists).WhereT(func(a *models.ResourcePoJo) bool {
			return strings.ToLower(a.Name) == strings.ToLower(r.Name)
		}).First()
		if one != nil {
			*curResource = one.(*models.ResourcePoJo).Resource
		} else {
			curResource.Status = enums.Enable.Value()
		}
		curResource.Name = r.Name
		if &r.Meta != nil {
			if r.Meta.Title == "" {
				continue
			}
			curResource.Title = r.Meta.Title
			if len(r.Meta.Access) > 0 {
				curResource.AuthorCode = strings.Join(r.Meta.Access, ",")
			}
		}
		curResource.ResType = enums.MENU.Value()
		curResource.ParentId = pid
		if curResource.ID > 0 {
			service.ResourceServiceInstance().Update(curResource)
			*forSaveIds = append(*forSaveIds, curResource.ID)
		} else {
			curResource.ID = snowflake.GenID()
			service.ResourceServiceInstance().Insert(curResource)
		}
		dealRouters(r.Children, curResource.ID, exists, forSaveIds)
		dealAction(r, curResource, exists, forSaveIds)
	}
}

func dealAction(r bus.Router, cur *models.Resource, exists []*models.ResourcePoJo, forSaveIds *[]int64) {
	if &r.Meta != nil && len(r.Meta.Actions) > 0 {
		for _, r := range r.Meta.Actions {
			curAction := new(models.Resource)
			one := linq.From(exists).WhereT(func(a *models.ResourcePoJo) bool {
				return strings.ToLower(a.Name) == strings.ToLower(r.Name)
			}).First()
			if one != nil {
				*curAction = one.(*models.ResourcePoJo).Resource
			} else {
				curAction.Status = enums.Enable.Value()
			}
			if r.Title == "" {
				continue
			}
			curAction.Name = r.Name
			curAction.Title = r.Title
			if len(r.Access) > 0 {
				curAction.AuthorCode = strings.Join(r.Access, ",")
			}
			curAction.ResType = enums.ACTION.Value()
			curAction.ParentId = cur.ID
			if curAction.ID > 0 {
				service.ResourceServiceInstance().Update(curAction)
				*forSaveIds = append(*forSaveIds, curAction.ID)
			} else {
				curAction.ID = snowflake.GenID()
				service.ResourceServiceInstance().Insert(curAction)
			}
		}
	}
}
